package main

import (
	"fmt"
	"strings"
)

type Person1 struct {
	FirstName string
	LastName  string
	Age       int
}

func upPerson(p *Person1) {
	p.FirstName = strings.ToUpper(p.FirstName)
	p.LastName = strings.ToUpper(p.LastName)
}

func main() {
	// 1- struct as a value type:
	var per1 Person1
	per1.FirstName = "Chris"
	per1.LastName = "Woodward"
	per1.Age = 37
	upPerson(&per1)
	fmt.Printf("The name of the person is %s %s\n", per1.FirstName, per1.LastName)

	//2- struct as a pointer type:
	per2 := &Person1{"Chris", "Woodward", 37}
	upPerson(per2)
	fmt.Printf("The name of the person is %s %s\n", per2.FirstName, per2.LastName)

	//3- struct as a literal type:
	per3 := Person1{"Chris", "Woodward", 37}
	upPerson(&per3)
	fmt.Printf("The name of the person is %s %s\n", per3.FirstName, per3.LastName)
	//per2 := &Person1{"Chris", "Woodward", 37}和per3 := Person1{"Chris", "Woodward", 37}主要区别在于指针类型和值类型的使用
	/**
	per2 := &Person1{"Chris", "Woodward", 37}
	per2是一个指针类型，指向一个Person1结构体的指针*Person1，它的值是一个堆上内存的地址
	当使用&Person1{}时，Person1对象实际数据存储在堆上，
	访问和修改per2时，会通过指针来操作Person1实例的数据

	per3 := Person1{"Chris", "Woodward", 37}
	per3是一个值类型，它直接存储在栈上（如果不逃逸到堆中）
	当操作per3时，操作的是该结构体的副本数据
	*/
	per3.FirstName = "John"
	upPerson(&per3)
	fmt.Printf("The name of the person is %s %s\n", per3.FirstName, per3.LastName)
}

/**
output:
The name of the person is CHRIS WOODWARD
The name of the person is CHRIS WOODWARD
The name of the person is CHRIS WOODWARD
*/
